﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AForge.Neuro;
using AForge.Neuro.Learning;
using System.IO;
using System.Drawing;

namespace redes_neuronales_ocr
{
    class RedNeuronal : Network
    {
        /* crea la red neuronal pasándole la cantidad de capas que tendrá y la cantidad de entradas inicial;
         se toma que la cantidad de neuronas de cada capa, es igual a la cantidad de entradas inicial*/
        public RedNeuronal(int cantidadDeEntradas, int cantidadDeCapas)
            : base(cantidadDeEntradas, cantidadDeCapas)
        {
                //for (int i = 0; i < this.layersCount; i++)
                //    this.layers[i] = new Capa(cantidadDeEntradas, cantidadDeEntradas);
        }


        /* carga la red neuronal desde el path del archivo pasado */
        public RedNeuronal(int cantidadDeEntradas, int cantidadDeCapas, string path)
            : base(cantidadDeEntradas, cantidadDeCapas)
        {
            Load(path);
        }


        /* recibe el vector de entrada inicial a la red, y retorna la salida de la última capa */
        public override double[] Compute(double[] input)
        {
            return base.Compute(input);
        }



        /*
         * Recibe las imagenes de aprendizaje vectorizadas y
         * entrena la red.
         * POR EL MOMENTO TAMBIEN LEVANTA UNA IMAGEN DE PRUEBA PARA RECONOCER
         * PERO HABRIA QUE SACARLO DE ESTE METODO.
         */
        public static void aprenderYReconocer(double[][] input, int cantEntradas) {
            // Estos patrones de salida son inventados para probar
            //double[][] outputIdeal = { new[] { 1.0, 0.0, 0.0, 0.0 }, // 0 
            //                     new[] { 0.0, 1.0, 0.0, 0.0 }  // 1 
            //                   };

            //ESTE PATRON NO FUNCIONA MUY BIEN
            double[][] outputIdeal = { new[] { 0.0, 0.0, 0.0, 0.0 }, // 0 
                                         new[] { 0.0, 0.0, 0.0, 1.0 }, // 1
                                         new[] { 0.0, 0.0, 1.0, 0.0 }, // 2
                                         new[] { 0.0, 0.0, 1.0, 1.0 }, // 3
                                         new[] { 0.0, 1.0, 0.0, 0.0 }, // 4
                                         new[] { 0.0, 1.0, 0.0, 1.0 }, // 5
                                         new[] { 0.0, 1.0, 1.0, 0.0 }, // 6
                                         new[] { 0.0, 1.0, 1.0, 1.0 }, // 7
                                         new[] { 1.0, 0.0, 0.0, 0.0 }, // 8
                                         new[] { 1.0, 0.0, 0.0, 1.0 }, // 9
                               };

            // ESTOS PATRONES NO FUNCAN, GENERAN ERROR ALTO
            //double[][] outputIdeal = { new[] { 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }, // 0 
            //                             new[] { 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }, // 1
            //                             new[] { 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }, // 2
            //                             new[] { 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }, // 3
            //                             new[] { 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0 }, // 4
            //                             new[] { 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0 }, // 5
            //                             new[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0 }, // 6
            //                             new[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, // 7
            //                             new[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0 }, // 8
            //                             new[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0 }  // 9
            //                   };

            IActivationFunction funcionActivacion = new SigmoidFunction();
            ActivationNetwork red = new ActivationNetwork(funcionActivacion, cantEntradas, 4);
            red.Randomize();
            BackPropagationLearning aprendizaje = new BackPropagationLearning(red);
            aprendizaje.LearningRate = 0.5;

            bool needToStop = false;
            int iteration = 0;
            while (!needToStop)
            {
                double error = aprendizaje.RunEpoch(input, outputIdeal);
                if (error == 0)
                    break;
                else if (iteration < 1000)
                    iteration++;
                else
                    needToStop = true;
                System.Diagnostics.Debug.WriteLine("{0} {1}", error, iteration);
            }

            // Levanta una imagen de la carpeta reconocimiento
            double[] muestraAReconocer = obtenerImagenParaReconocer();

            // Computa y devuelve resultado
            // El vector resultado deberia ser similar al patron del outputIdeal
            double[] resultado = red.Compute(muestraAReconocer);

            // Imprimo el vector para ver que sale
            // Se puede ver que no se parece a ningun patron del outputIdeal =(
            foreach (double d in resultado)
            {
                Console.WriteLine(d.ToString());
            }
            Console.ReadKey();
        }

        /*
         * METODO AUX TEMPORAL:
         * Levanta una unica imagen para reconocer
         * y la devuelve vectorizada.
         */
        private static double[] obtenerImagenParaReconocer()
        {
            double[] resultado = null;
            string pathImgReconocimiento = "C:\\Users\\Sebass\\Desktop\\Inteligencia Artificial\\workspace\\redes-neuronales-ocr\\redes-neuronales-ocr\\img-reconocimiento";
            DirectoryInfo directoryInfo = new DirectoryInfo(pathImgReconocimiento);
            // Obtengo todas las imagenes de la carpeta
            FileInfo[] fileInfo = directoryInfo.GetFiles();
            //Por cada imagen, la paso a un array de 1 y 0.
            for (int i = 0; i < fileInfo.Length; i++)
            {
                string rutaImagen = fileInfo[i].FullName;
                Bitmap imagen = new Bitmap(rutaImagen);
                //resultado = ProcesamientoDeImagen.procesarImagen(imagen);
                resultado = ProcesamientoDeImagen.procesarImagen2(imagen);
            }
            return resultado;
        }

    }
}
